home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume12 / afio / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-10-25  |  31.5 KB

  1. Subject:  v12i047:  Manipulate CPIO-format archive and files, Part02/02
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: Mark Brukhartz <ihnp4!laidbak!mdb>
  7. Posting-number: Volume 12, Issue 47
  8. Archive-name: afio/part02
  9.  
  10. [  This is a replacement for cpio, a (tape-) archive program.  I wrote the
  11.    Makefile.  I had to split the source file into two halves, which will
  12.    need to be joined together.  --r$ ]
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 2 (of 2)."
  21. # Contents:  afio.c.P1
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f 'afio.c.P1' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'afio.c.P1'\"
  25. else
  26. echo shar: Extracting \"'afio.c.P1'\" \(29675 characters\)
  27. sed "s/^X//" >'afio.c.P1' <<'END_OF_FILE'
  28. X/*
  29. X * afio.c
  30. X *
  31. X * Manipulate archives and files.
  32. X *
  33. X * Copyright (c) 1985 Lachman Associates, Inc..
  34. X *
  35. X * This software was written by Mark Brukhartz at Lachman Associates,
  36. X * Inc.. It may be distributed within the following restrictions:
  37. X *    (1) It may not be sold at a profit.
  38. X *    (2) This credit and notice must remain intact.
  39. X * This software may be distributed with other software by a commercial
  40. X * vendor, provided that it is included at no additional charge.
  41. X *
  42. X * Please report bugs to "..!ihnp4!laidbak!mdb".
  43. X *
  44. X * Options:
  45. X *  o Define INDEX to use index() in place of strchr() (v7, BSD).
  46. X *  o Define MEMCPY when an efficient memcpy() exists (SysV).
  47. X *  o Define MKDIR when a mkdir() system call is present (4.2BSD, SysVr3).
  48. X *  o Define NOVOID if your compiler doesn't like void casts.
  49. X *  o Define SYSTIME to use <sys/time.h> rather than <time.h> (4.2BSD).
  50. X *  o Define VOIDFIX to allow pointers to functions returning void (non-PCC).
  51. X *  o Define CTC3B2 to support AT&T 3B2 streaming cartridge tape.
  52. X */
  53. X
  54. Xstatic char *ident = "$Header: afio.c,v 1.68 86/12/15 13:07:11 mdb Exp $";
  55. X
  56. X#include <stdio.h>
  57. X#include <errno.h>
  58. X#include <sys/signal.h>
  59. X#include <sys/types.h>
  60. X#include <sys/ioctl.h>
  61. X#include <sys/stat.h>
  62. X#include <pwd.h>
  63. X#include <grp.h>
  64. X
  65. X#ifndef    major
  66. X#    include <sys/sysmacros.h>
  67. X#endif    /* major */
  68. X
  69. X#ifdef    SYSTIME
  70. X#    include <sys/time.h>
  71. X#else    /* SYSTIME */
  72. X#    include <time.h>
  73. X#endif    /* SYSTIME */
  74. X
  75. X#ifdef    CTC3B2
  76. X#    include <sys/vtoc.h>
  77. X#    include <sys/ct.h>
  78. X#endif    /* CTC3B2 */
  79. X
  80. X/*
  81. X * Address link information base.
  82. X */
  83. X#define    linkhash(ino)    \
  84. X    (linkbase + (ino) % nel(linkbase))
  85. X
  86. X/*
  87. X * Mininum value.
  88. X */
  89. X#define    min(one, two)    \
  90. X    (one < two ? one : two)
  91. X
  92. X/*
  93. X * Number of array elements.
  94. X */
  95. X#define    nel(a)        \
  96. X    (sizeof(a) / sizeof(*(a)))
  97. X
  98. X/*
  99. X * Remove a file or directory.
  100. X */
  101. X#define    remove(name, asb) \
  102. X    (((asb)->sb_mode & S_IFMT) == S_IFDIR ? rmdir(name) : unlink(name))
  103. X
  104. X/*
  105. X * Swap bytes.
  106. X */
  107. X#define    swab(n)        \
  108. X    ((((ushort)(n) >> 8) & 0xff) | (((ushort)(n) << 8) & 0xff00))
  109. X
  110. X/*
  111. X * Cast and reduce to unsigned short.
  112. X */
  113. X#define    ush(n)        \
  114. X    (((ushort) (n)) & 0177777)
  115. X
  116. X/*
  117. X * Definitions.
  118. X */
  119. X#define    reg    register    /* Convenience */
  120. X#define    uint    unsigned int    /* Not always in types.h */
  121. X#define    ushort    unsigned short    /* Not always in types.h */
  122. X#define    BLOCK    5120        /* Default archive block size */
  123. X#define    FSBUF    (8*1024)    /* Filesystem buffer size */
  124. X#define    H_COUNT    10        /* Number of items in ASCII header */
  125. X#define    H_PRINT    "%06o%06o%06o%06o%06o%06o%06o%011lo%06o%011lo"
  126. X#define    H_SCAN    "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6o%11lo"
  127. X#define    H_STRLEN 70        /* ASCII header string length */
  128. X#define    M_ASCII "070707"    /* ASCII magic number */
  129. X#define    M_BINARY 070707        /* Binary magic number */
  130. X#define    M_STRLEN 6        /* ASCII magic number length */
  131. X#define    NULLDEV    -1        /* Null device code */
  132. X#define    NULLINO    0        /* Null inode number */
  133. X#define    PATHELEM 256        /* Pathname element count limit */
  134. X#define    PATHSIZE 1024        /* Pathname length limit */
  135. X#define    S_IFSHF    12        /* File type shift (shb in stat.h) */
  136. X#define    S_IPERM    07777        /* File permission bits (shb in stat.h) */
  137. X#define    S_IPEXE    07000        /* Special execution bits (shb in stat.h) */
  138. X#define    S_IPOPN    0777        /* Open access bits (shb in stat.h) */
  139. X#define    STDIN    0        /* Standard input file descriptor */
  140. X#define    STDOUT    1        /* Standard output file descriptor */
  141. X#define    TTY    "/dev/tty"    /* For volume-change queries */
  142. X
  143. X/*
  144. X * Some versions of the portable "C" compiler (PCC) can't handle
  145. X * pointers to functions returning void.
  146. X */
  147. X#ifdef    VOIDFIX
  148. X#    define    VOIDFN    void    /* Expect "void (*fnptr)()" to work */
  149. X#else    /* VOIDFIX */
  150. X#    define    VOIDFN    int    /* Avoid PCC "void (*fnptr)()" bug */
  151. X#endif    /* VOIDFIX */
  152. X
  153. X/*
  154. X * Trailer pathnames. All must be of the same length.
  155. X */
  156. X#define    TRAILER    "TRAILER!!!"    /* Archive trailer (cpio compatible) */
  157. X#define    TRAILZ    11        /* Trailer pathname length (including null) */
  158. X
  159. X/*
  160. X * Open modes; there is no <fcntl.h> with v7 UNIX.
  161. X */
  162. X#define    O_RDONLY 0        /* Read-only */
  163. X#define    O_WRONLY 1        /* Write-only */
  164. X#define    O_RDWR    2        /* Read/write */
  165. X
  166. X/*
  167. X * V7 and BSD UNIX use old-fashioned names for a couple of
  168. X * string functions.
  169. X */
  170. X#ifdef    INDEX
  171. X#    define    strchr    index    /* Forward character search */
  172. X#    define    strrchr    rindex    /* Reverse character search */
  173. X#endif    /* INDEX */
  174. X
  175. X/*
  176. X * Some compilers can't handle void casts.
  177. X */
  178. X#ifdef    NOVOID
  179. X#    define    VOID        /* Omit void casts */
  180. X#else    /* NOVOID */
  181. X#    define    VOID    (void)    /* Quiet lint about ignored return values */
  182. X#endif    /* NOVOID */
  183. X
  184. X/*
  185. X * Adb is more palatable when static functions and variables are
  186. X * declared as globals. Lint gives more useful information when
  187. X * statics are truly static.
  188. X */
  189. X#ifdef    lint
  190. X#    define    STATIC    static    /* Declare static variables for lint */
  191. X#else    /* lint */
  192. X#    define    STATIC        /* Make static variables global for adb */
  193. X#endif    /* lint */
  194. X
  195. X/*
  196. X * Simple types.
  197. X */
  198. Xtypedef struct group    Group;    /* Structure for getgrgid(3) */
  199. Xtypedef struct passwd    Passwd;    /* Structure for getpwuid(3) */
  200. Xtypedef struct tm    Time;    /* Structure for localtime(3) */
  201. X
  202. X#ifdef    S_IFLNK
  203. X    /*
  204. X     * File status with symbolic links. Kludged to hold symbolic
  205. X     * link pathname within structure.
  206. X     */
  207. X    typedef struct {
  208. X        struct stat    sb_stat;
  209. X        char        sb_link[PATHSIZE];
  210. X    } Stat;
  211. X#    define    STAT(name, asb)        stat(name, &(asb)->sb_stat)
  212. X#    define    FSTAT(fd, asb)        fstat(fd, &(asb)->sb_stat)
  213. X#    define    LSTAT(name, asb)    lstat(name, &(asb)->sb_stat)
  214. X#    define    sb_dev        sb_stat.st_dev
  215. X#    define    sb_ino        sb_stat.st_ino
  216. X#    define    sb_mode        sb_stat.st_mode
  217. X#    define    sb_nlink    sb_stat.st_nlink
  218. X#    define    sb_uid        sb_stat.st_uid
  219. X#    define    sb_gid        sb_stat.st_gid
  220. X#    define    sb_rdev        sb_stat.st_rdev
  221. X#    define    sb_size        sb_stat.st_size
  222. X#    define    sb_atime    sb_stat.st_atime
  223. X#    define    sb_mtime    sb_stat.st_mtime
  224. X#    define    sb_ctime    sb_stat.st_ctime
  225. X#    define    sb_blksize    sb_stat.st_blksize
  226. X#    define    sb_blocks    sb_stat.st_blocks
  227. X#else    /* S_IFLNK */
  228. X    /*
  229. X     * File status without symbolic links.
  230. X     */
  231. X    typedef    struct stat    Stat;
  232. X#    define    STAT(name, asb)        stat(name, asb)
  233. X#    define    FSTAT(fd, asb)        fstat(fd, asb)
  234. X#    define    LSTAT(name, asb)    stat(name, asb)
  235. X#    define    sb_dev        st_dev
  236. X#    define    sb_ino        st_ino
  237. X#    define    sb_mode        st_mode
  238. X#    define    sb_nlink    st_nlink
  239. X#    define    sb_uid        st_uid
  240. X#    define    sb_gid        st_gid
  241. X#    define    sb_rdev        st_rdev
  242. X#    define    sb_size        st_size
  243. X#    define    sb_atime    st_atime
  244. X#    define    sb_mtime    st_mtime
  245. X#    define    sb_ctime    st_ctime
  246. X#endif    /* S_IFLNK */
  247. X
  248. X/*
  249. X * Binary archive header (obsolete).
  250. X */
  251. Xtypedef struct {
  252. X    short    b_dev;            /* Device code */
  253. X    ushort    b_ino;            /* Inode number */
  254. X    ushort    b_mode;            /* Type and permissions */
  255. X    ushort    b_uid;            /* Owner */
  256. X    ushort    b_gid;            /* Group */
  257. X    short    b_nlink;        /* Number of links */
  258. X    short    b_rdev;            /* Real device */
  259. X    ushort    b_mtime[2];        /* Modification time (hi/lo) */
  260. X    ushort    b_name;            /* Length of pathname (with null) */
  261. X    ushort    b_size[2];        /* Length of data */
  262. X} Binary;
  263. X
  264. X/*
  265. X * Child process structure.
  266. X */
  267. Xtypedef struct child {
  268. X    struct child    *c_forw;    /* Forward link */
  269. X    int        c_pid;        /* Process ID */
  270. X    int        c_flags;    /* Flags (CF_) */
  271. X    int        c_status;    /* Exit status */
  272. X} Child;
  273. X
  274. X/*
  275. X * Child process flags (c_flags).
  276. X */
  277. X#define    CF_EXIT    (1<<0)            /* Exited */
  278. X
  279. X/*
  280. X * Hard link sources. One or more are chained from each link
  281. X * structure.
  282. X */
  283. Xtypedef struct name {
  284. X    struct name    *p_forw;    /* Forward chain (terminated) */
  285. X    struct name    *p_back;    /* Backward chain (circular) */
  286. X    char        *p_name;    /* Pathname to link from */
  287. X} Path;
  288. X
  289. X/*
  290. X * File linking information. One entry exists for each unique
  291. X * file with with outstanding hard links.
  292. X */
  293. Xtypedef struct link {
  294. X    struct link    *l_forw;    /* Forward chain (terminated) */
  295. X    struct link    *l_back;    /* Backward chain (terminated) */
  296. X    dev_t        l_dev;        /* Device */
  297. X    ino_t        l_ino;        /* Inode */
  298. X    ushort        l_nlink;    /* Unresolved link count */
  299. X    off_t        l_size;        /* Length */
  300. X    Path        *l_path;    /* Pathname(s) to link from */
  301. X} Link;
  302. X
  303. X/*
  304. X * Pathnames to (or to not) be processed.
  305. X */
  306. Xtypedef struct pattern {
  307. X    struct pattern    *p_forw;    /* Forward chain */
  308. X    char        *p_str;        /* String */
  309. X    int        p_len;        /* Length of string */
  310. X    int        p_not;        /* Reverse logic */
  311. X} Pattern;
  312. X
  313. X/*
  314. X * External functions.
  315. X */
  316. Xvoid    _exit();
  317. Xvoid    exit();
  318. Xvoid    free();
  319. Xchar    *getenv();
  320. Xushort    getgid();
  321. XGroup    *getgrgid();
  322. XPasswd    *getpwuid();
  323. Xushort    getuid();
  324. XTime    *localtime();
  325. Xoff_t    lseek();
  326. Xchar    *malloc();
  327. XVOIDFN    (*signal())();
  328. Xuint    sleep();
  329. Xchar    *strcat();
  330. Xchar    *strchr();
  331. Xchar    *strcpy();
  332. Xchar    *strncpy();
  333. Xchar    *strrchr();
  334. Xtime_t    time();
  335. Xushort    umask();
  336. X
  337. X/*
  338. X * Internal functions.
  339. X */
  340. XVOIDFN    copyin();
  341. XVOIDFN    copyout();
  342. Xint    dirchg();
  343. Xint    dirmake();
  344. Xint    dirneed();
  345. Xvoid    fatal();
  346. XVOIDFN    in();
  347. Xvoid    inalloc();
  348. Xint    inascii();
  349. Xint    inavail();
  350. Xint    inbinary();
  351. Xint    indata();
  352. Xint    inentry();
  353. Xint    infill();
  354. Xint    inhead();
  355. Xint    inread();
  356. Xint    inskip();
  357. Xint    inswab();
  358. Xint    lineget();
  359. Xvoid    linkalso();
  360. XLink    *linkfrom();
  361. Xvoid    linkleft();
  362. XLink    *linkto();
  363. Xvoid    memcpy();
  364. Xchar    *memget();
  365. Xchar    *memstr();
  366. Xint    mkdir();
  367. Xvoid    nameadd();
  368. Xint    namecmp();
  369. Xint    nameopt();
  370. Xvoid    next();
  371. Xvoid    nextask();
  372. Xvoid    nextclos();
  373. Xint    nextopen();
  374. Xint    openi();
  375. Xint    openo();
  376. Xint    openq();
  377. Xint    options();
  378. Xoff_t    optsize();
  379. XVOIDFN    out();
  380. Xvoid    outalloc();
  381. Xuint    outavail();
  382. Xint    outdata();
  383. Xvoid    outeof();
  384. Xvoid    outflush();
  385. Xvoid    outhead();
  386. Xvoid    outpad();
  387. Xvoid    outwait();
  388. Xvoid    outwrite();
  389. XVOIDFN    pass();
  390. Xvoid    passdata();
  391. Xint    passitem();
  392. Xint    pipechld();
  393. Xint    pipeopen();
  394. Xvoid    pipewait();
  395. Xvoid    prsize();
  396. Xint    rmdir();
  397. Xint    swrite();
  398. Xchar    *syserr();
  399. XVOIDFN    toc();
  400. Xvoid    tocentry();
  401. Xvoid    tocmode();
  402. Xvoid    usage();
  403. Xint    warn();
  404. Xint    warnarch();
  405. Xint    xfork();
  406. Xvoid    xpause();
  407. Xint    xwait();
  408. X
  409. X/*
  410. X * External variables.
  411. X */
  412. Xextern int    errno;        /* System error code */
  413. Xextern char    *sys_errlist[];    /* System error messages */
  414. Xextern int    sys_nerr;    /* Number of sys_errlist entries */
  415. X
  416. X/*
  417. X * Static variables.
  418. X */
  419. X#ifdef    CTC3B2
  420. XSTATIC short    Cflag;        /* Enable 3B2 CTC streaming (kludge) */
  421. X#endif    /* CTC3B2 */
  422. XSTATIC short    dflag;        /* Don't create missing directories */
  423. XSTATIC short    fflag;        /* Fork before writing to archive */
  424. XSTATIC short    gflag;        /* Change to input file directories */
  425. XSTATIC short    hflag;        /* Follow symbolic links */
  426. XSTATIC short    jflag;        /* Don't generate sparse filesystem blocks */
  427. XSTATIC short    kflag;        /* Skip initial junk to find a header */
  428. XSTATIC short    lflag;        /* Link rather than copying (when possible) */
  429. XSTATIC short    mflag;        /* Ignore archived timestamps */
  430. XSTATIC short    nflag;        /* Keep newer existing files */
  431. XSTATIC short    uflag;        /* Report files with unseen links */
  432. XSTATIC short    vflag;        /* Verbose */
  433. XSTATIC short    xflag;        /* Retain file ownership */
  434. XSTATIC short    zflag;        /* Print final statistics */
  435. XSTATIC uint    arbsize = BLOCK;/* Archive block size */
  436. XSTATIC short    areof;        /* End of input volume reached */
  437. XSTATIC int    arfd;        /* Archive file descriptor */
  438. XSTATIC off_t    arleft;        /* Space remaining within current volume */
  439. XSTATIC char    *arname;    /* Expanded archive name */
  440. XSTATIC uint    arpad;        /* Final archive block padding boundary */
  441. XSTATIC char    arspec[PATHSIZE];/* Specified archive name */
  442. XSTATIC off_t    aruntil;    /* Volume size limit */
  443. XSTATIC uint    arvolume;    /* Volume number */
  444. XSTATIC uint    buflen;        /* Archive buffer length */
  445. XSTATIC char    *buffer;    /* Archive buffer */
  446. XSTATIC char    *bufidx;    /* Archive buffer index */
  447. XSTATIC char    *bufend;    /* End of data within archive buffer */
  448. XSTATIC Child    *children;    /* Child processes */
  449. XSTATIC ushort    gid;        /* Group ID */
  450. XSTATIC Link    *linkbase[256];    /* Unresolved link information */
  451. XSTATIC ushort    mask;        /* File creation mask */
  452. XSTATIC char    *myname;    /* Arg0 */
  453. XSTATIC char    *optarg;    /* Option argument */
  454. XSTATIC int    optind;        /* Command line index */
  455. XSTATIC int    outpid;        /* Process ID of outstanding outflush() */
  456. XSTATIC Pattern    *pattern;    /* Pathname matching patterns */
  457. XSTATIC char    pwd[PATHSIZE];    /* Working directory (with "-g") */
  458. XSTATIC int    pipepid;    /* Pipeline process ID */
  459. XSTATIC time_t    timenow;    /* Current time */
  460. XSTATIC time_t    timewait;    /* Time spent awaiting new media */
  461. XSTATIC off_t    total;        /* Total number of bytes transferred */
  462. XSTATIC int    ttyf;        /* For interactive queries (yuk) */
  463. XSTATIC ushort    uid;        /* User ID */
  464. X
  465. Xmain(ac, av)
  466. Xint        ac;
  467. Xreg char    **av;
  468. X{
  469. X    reg int        c;
  470. X    reg uint    group = 1;
  471. X    reg VOIDFN    (*fn)() = NULL;
  472. X    reg time_t    timedone;
  473. X    auto char    remote[PATHSIZE];
  474. X
  475. X    if (myname = strrchr(*av, '/'))
  476. X        ++myname;
  477. X    else
  478. X        myname = *av;
  479. X    mask = umask(0);
  480. X    ttyf = openq();
  481. X    uid = getuid();
  482. X    gid = getgid();
  483. X    if (uid == 0)
  484. X        ++xflag;
  485. X    VOID signal(SIGPIPE, SIG_IGN);
  486. X    while (c = options(ac, av, "ioptIOVCb:c:de:fghjklmns:uvxXy:Y:z")) {
  487. X        switch (c) {
  488. X        case 'i':
  489. X            if (fn)
  490. X                usage();
  491. X            fn = in;
  492. X            break;
  493. X        case 'o':
  494. X            if (fn)
  495. X                usage();
  496. X            fn = out;
  497. X            break;
  498. X        case 'p':
  499. X            if (fn)
  500. X                usage();
  501. X            fn = pass;
  502. X            break;
  503. X        case 't':
  504. X            if (fn)
  505. X                usage();
  506. X            fn = toc;
  507. X            break;
  508. X        case 'I':
  509. X            if (fn)
  510. X                usage();
  511. X            fn = copyin;
  512. X            break;
  513. X        case 'O':
  514. X            if (fn)
  515. X                usage();
  516. X            fn = copyout;
  517. X            break;
  518. X        case 'V':
  519. X            VOID printf("%s\n", ident);
  520. X            exit(0);
  521. X#ifdef    CTC3B2
  522. X        case 'C':
  523. X            ++Cflag;
  524. X            arbsize = 31 * 512;
  525. X            group = 10;
  526. X            aruntil = 1469 * 31 * 512;
  527. X            break;
  528. X#endif    /* CTC3B2 */
  529. X        case 'b':
  530. X            if ((arbsize = (uint) optsize(optarg)) == 0)
  531. X                fatal(optarg, "Bad block size");
  532. X            break;
  533. X        case 'c':
  534. X            if ((group = (uint) optsize(optarg)) == 0)
  535. X                fatal(optarg, "Bad buffer count");
  536. X            break;
  537. X        case 'd':
  538. X            ++dflag;
  539. X            break;
  540. X        case 'e':
  541. X            arpad = (uint) optsize(optarg);
  542. X            break;
  543. X        case 'f':
  544. X            ++fflag;
  545. X            break;
  546. X        case 'g':
  547. X            ++gflag;
  548. X            break;
  549. X        case 'h':
  550. X            ++hflag;
  551. X            break;
  552. X        case 'j':
  553. X            ++jflag;
  554. X            break;
  555. X        case 'k':
  556. X            ++kflag;
  557. X            break;
  558. X        case 'l':
  559. X            ++lflag;
  560. X            break;
  561. X        case 'm':
  562. X            ++mflag;
  563. X            break;
  564. X        case 'n':
  565. X            ++nflag;
  566. X            break;
  567. X        case 's':
  568. X            aruntil = optsize(optarg);
  569. X            break;
  570. X        case 'u':
  571. X            ++uflag;
  572. X            break;
  573. X        case 'v':
  574. X            ++vflag;
  575. X            break;
  576. X        case 'x':
  577. X            ++xflag;
  578. X            break;
  579. X        case 'X':
  580. X            xflag = 0;
  581. X            break;
  582. X        case 'y':
  583. X            nameadd(optarg, 0);
  584. X            break;
  585. X        case 'Y':
  586. X            nameadd(optarg, 1);
  587. X            break;
  588. X        case 'z':
  589. X            ++zflag;
  590. X            break;
  591. X        default:
  592. X            usage();
  593. X        }
  594. X    }
  595. X    if (fn == NULL || av[optind] == NULL)
  596. X        usage();
  597. X    buflen = arbsize * group;
  598. X    if (arpad == 0)
  599. X        arpad = arbsize;
  600. X    if (fn != pass) {
  601. X        reg char    *colon;
  602. X        reg char    *equal;
  603. X        reg int        isoutput = (fn == out || fn == copyout);
  604. X
  605. X        arname = strcpy(arspec, av[optind++]);
  606. X        if (colon = strchr(arspec, ':')) {
  607. X            *colon++ = '\0';
  608. X            if (equal = strchr(arspec, '='))
  609. X                *equal++ = '\0';
  610. X            VOID sprintf(arname = remote,
  611. X                "!rsh %s %s -%c -b %u -c %u %s",
  612. X                arspec, equal ? equal : myname,
  613. X                isoutput ? 'O' : 'I', arbsize,
  614. X                group, colon);
  615. X            if (equal)
  616. X                *--equal = '=';
  617. X            *--colon = ':';
  618. X        }
  619. X        if (gflag && *arname != '/' && *arname != '!')
  620. X            fatal(arspec, "Relative pathname");
  621. X        if ((buffer = bufidx = bufend = malloc(buflen)) == NULL)
  622. X            fatal(arspec, "Cannot allocate I/O buffer");
  623. X        if (nextopen(isoutput ? O_WRONLY : O_RDONLY) < 0)
  624. X            exit(1);
  625. X    }
  626. X    timenow = time((time_t *) NULL);
  627. X    (*fn)(av + optind);
  628. X    timedone = time((time_t *) NULL);
  629. X    if (uflag)
  630. X        linkleft();
  631. X    if (zflag) {
  632. X        reg FILE    *stream;
  633. X
  634. X        stream = fn == toc || arfd == STDOUT ? stderr : stdout;
  635. X        VOID fprintf(stream, "%s: ", myname);
  636. X        prsize(stream, total);
  637. X        VOID fprintf(stream, " bytes %s in %lu seconds\n",
  638. X          fn == pass
  639. X            ? "transferred"
  640. X            : fn == out || fn == copyout
  641. X              ? "written"
  642. X              : "read",
  643. X          timedone - timenow - timewait);
  644. X    }
  645. X    nextclos();
  646. X    exit(0);
  647. X    /* NOTREACHED */
  648. X}
  649. X
  650. X/*
  651. X * copyin()
  652. X *
  653. X * Copy directly from the archive to the standard output.
  654. X */
  655. XSTATIC VOIDFN
  656. Xcopyin(av)
  657. Xreg char    **av;
  658. X{
  659. X    reg int        got;
  660. X    reg uint    have;
  661. X
  662. X    if (*av)
  663. X        fatal(*av, "Extraneous argument");
  664. X    while (!areof) {
  665. X        VOID infill();
  666. X        while (have = bufend - bufidx)
  667. X            if ((got = write(STDOUT, bufidx, have)) < 0)
  668. X                fatal("<stdout>", syserr());
  669. X            else if (got > 0)
  670. X                bufidx += got;
  671. X            else
  672. X                return;
  673. X    }
  674. X}
  675. X
  676. X/*
  677. X * copyout()
  678. X *
  679. X * Copy directly from the standard input to the archive.
  680. X */
  681. XSTATIC VOIDFN
  682. Xcopyout(av)
  683. Xreg char    **av;
  684. X{
  685. X    reg int        got;
  686. X    reg uint    want;
  687. X
  688. X    if (*av)
  689. X        fatal(*av, "Extraneous argument");
  690. X    for (;;) {
  691. X        while ((want = bufend - bufidx) == 0)
  692. X            outflush();
  693. X        if ((got = read(STDIN, bufidx, want)) < 0)
  694. X            fatal("<stdin>", syserr());
  695. X        else if (got == 0)
  696. X            break;
  697. X        else
  698. X            bufidx += got;
  699. X    }
  700. X    outflush();
  701. X    if (fflag)
  702. X        outwait();
  703. X}
  704. X
  705. X/*
  706. X * dirchg()
  707. X *
  708. X * Change to the directory containing a given file.
  709. X */
  710. XSTATIC int
  711. Xdirchg(name, local)
  712. Xreg char    *name;
  713. Xreg char    *local;
  714. X{
  715. X    reg char    *last;
  716. X    reg int        len;
  717. X    auto char    dir[PATHSIZE];
  718. X
  719. X    if (*name != '/')
  720. X        return (warn(name, "Relative pathname"));
  721. X    for (last = name + strlen(name); last[-1] != '/'; --last)
  722. X        ;
  723. X    len = last - name;
  724. X    strncpy(dir, name, len)[len] = '\0';
  725. X    VOID strcpy(local, *last ? last : ".");
  726. X    if (strcmp(dir, pwd) == 0)
  727. X        return (0);
  728. X    if (chdir(dir) < 0)
  729. X        return (warn(name, syserr()));
  730. X    VOID strcpy(pwd, dir);
  731. X    return (0);
  732. X}
  733. X
  734. X/*
  735. X * dirmake()
  736. X *
  737. X * Make a directory. Returns zero if successful, -1 otherwise.
  738. X */
  739. XSTATIC int
  740. Xdirmake(name, asb)
  741. Xreg char    *name;
  742. Xreg Stat    *asb;
  743. X{
  744. X    if (mkdir(name, asb->sb_mode & S_IPOPN) < 0)
  745. X        return (-1);
  746. X    if (asb->sb_mode & S_IPEXE)
  747. X        VOID chmod(name, asb->sb_mode & S_IPERM);
  748. X    if (xflag)
  749. X        VOID chown(name,
  750. X            uid == 0 ? ush(asb->sb_uid) : uid,
  751. X            ush(asb->sb_gid));
  752. X    return (0);
  753. X}
  754. X
  755. X/*
  756. X * dirneed()
  757. X *
  758. X * Recursively create missing directories (with the same permissions
  759. X * as their first existing parent). Temporarily modifies the 'name'
  760. X * argument string. Returns zero if successful, -1 otherwise.
  761. X */
  762. XSTATIC int
  763. Xdirneed(name)
  764. Xchar        *name;
  765. X{
  766. X    reg char    *cp;
  767. X    reg char    *last;
  768. X    reg int        ok;
  769. X    static Stat    sb;
  770. X
  771. X    last = NULL;
  772. X    for (cp = name; *cp; )
  773. X        if (*cp++ == '/')
  774. X            last = cp;
  775. X    if (last == NULL)
  776. X        return (STAT(".", &sb));
  777. X    *--last = '\0';
  778. X    ok = STAT(*name ? name : "/", &sb) == 0
  779. X        ? ((sb.sb_mode & S_IFMT) == S_IFDIR)
  780. X        : (!dflag && dirneed(name) == 0 && dirmake(name, &sb) == 0);
  781. X    *last = '/';
  782. X    return (ok ? 0 : -1);
  783. X}
  784. X
  785. X/*
  786. X * fatal()
  787. X *
  788. X * Print fatal message and exit.
  789. X */
  790. XSTATIC void
  791. Xfatal(what, why)
  792. Xchar        *what;
  793. Xchar        *why;
  794. X{
  795. X    VOID fprintf(stderr,
  796. X        "%s: \"%s\": %s\n",
  797. X        myname, what, why);
  798. X    exit(1);
  799. X}
  800. X
  801. X/*
  802. X * in()
  803. X *
  804. X * Read an archive.
  805. X */
  806. XSTATIC VOIDFN
  807. Xin(av)
  808. Xreg char    **av;
  809. X{
  810. X    auto Stat    sb;
  811. X    auto char    name[PATHSIZE];
  812. X
  813. X    if (*av)
  814. X        fatal(*av, "Extraneous argument");
  815. X    name[0] = '\0';
  816. X    while (inhead(name, &sb) == 0) {
  817. X        if (namecmp(name) < 0 || inentry(name, &sb) < 0)
  818. X            if (inskip(sb.sb_size) < 0)
  819. X                VOID warn(name, "Skipped file data is corrupt");
  820. X        if (vflag)
  821. X            VOID fprintf(stderr, "%s\n", name);
  822. X    }
  823. X}
  824. X
  825. X/*
  826. X * inalloc()
  827. X *
  828. X * Allocate input buffer space (which was previously indexed
  829. X * by inavail()).
  830. X */
  831. XSTATIC void
  832. Xinalloc(len)
  833. Xreg uint    len;
  834. X{
  835. X    bufidx += len;
  836. X    total += len;
  837. X}
  838. X
  839. X/*
  840. X * inascii()
  841. X *
  842. X * Read an ASCII header. Returns zero if successful;
  843. X * -1 otherwise. Assumes that the entire magic number
  844. X * has been read.
  845. X */
  846. XSTATIC int
  847. Xinascii(magic, name, asb)
  848. Xreg char    *magic;
  849. Xreg char    *name;
  850. Xreg Stat    *asb;
  851. X{
  852. X    auto uint    namelen;
  853. X    auto char    header[H_STRLEN + 1];
  854. X
  855. X    if (strncmp(magic, M_ASCII, M_STRLEN) != 0)
  856. X        return (-1);
  857. X    if (inread(header, H_STRLEN) < 0)
  858. X        return (warnarch("Corrupt ASCII header", (off_t) H_STRLEN));
  859. X    header[H_STRLEN] = '\0';
  860. X    if (sscanf(header, H_SCAN, &asb->sb_dev,
  861. X        &asb->sb_ino, &asb->sb_mode, &asb->sb_uid,
  862. X        &asb->sb_gid, &asb->sb_nlink, &asb->sb_rdev,
  863. X        &asb->sb_mtime, &namelen, &asb->sb_size) != H_COUNT)
  864. X        return (warnarch("Bad ASCII header", (off_t) H_STRLEN));
  865. X    if (namelen == 0 || namelen >= PATHSIZE)
  866. X        return (warnarch("Bad ASCII pathname length", (off_t) H_STRLEN));
  867. X    if (inread(name, namelen) < 0)
  868. X        return (warnarch("Corrupt ASCII pathname", (off_t) namelen));
  869. X    if (name[namelen - 1] != '\0')
  870. X        return (warnarch("Bad ASCII pathname", (off_t) namelen));
  871. X    return (0);
  872. X}
  873. X
  874. X/*
  875. X * inavail()
  876. X *
  877. X * Index availible input data within the buffer. Stores a pointer
  878. X * to the data and its length in given locations. Returns zero with
  879. X * valid data, -1 if unreadable portions were replaced with nulls.
  880. X */
  881. XSTATIC int
  882. Xinavail(bufp, lenp)
  883. Xreg char    **bufp;
  884. Xuint        *lenp;
  885. X{
  886. X    reg uint    have;
  887. X    reg int        corrupt = 0;
  888. X
  889. X    while ((have = bufend - bufidx) == 0)
  890. X        corrupt |= infill();
  891. X    *bufp = bufidx;
  892. X    *lenp = have;
  893. X    return (corrupt);
  894. X}
  895. X
  896. X/*
  897. X * inbinary()
  898. X *
  899. X * Read a binary header. Returns the number of trailing alignment
  900. X * bytes to skip; -1 if unsuccessful.
  901. X */
  902. XSTATIC int
  903. Xinbinary(magic, name, asb)
  904. Xreg char    *magic;
  905. Xreg char    *name;
  906. Xreg Stat    *asb;
  907. X{
  908. X    reg uint    namefull;
  909. X    auto Binary    binary;
  910. X
  911. X    if (*((ushort *) magic) != M_BINARY)
  912. X        return (-1);
  913. X    memcpy((char *) &binary,
  914. X        magic + sizeof(ushort),
  915. X        M_STRLEN - sizeof(ushort));
  916. X    if (inread((char *) &binary + M_STRLEN - sizeof(ushort),
  917. X        sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0)
  918. X        return (warnarch("Corrupt binary header",
  919. X            (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  920. X    asb->sb_dev = binary.b_dev;
  921. X    asb->sb_ino = binary.b_ino;
  922. X    asb->sb_mode = binary.b_mode;
  923. X    asb->sb_uid = binary.b_uid;
  924. X    asb->sb_gid = binary.b_gid;
  925. X    asb->sb_nlink = binary.b_nlink;
  926. X    asb->sb_rdev = binary.b_rdev;
  927. X    asb->sb_mtime = binary.b_mtime[0] << 16 | binary.b_mtime[1];
  928. X    asb->sb_size = binary.b_size[0] << 16 | binary.b_size[1];
  929. X    if (binary.b_name == 0 || binary.b_name >= PATHSIZE)
  930. X        return (warnarch("Bad binary pathname length",
  931. X            (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  932. X    if (inread(name, namefull = binary.b_name + binary.b_name % 2) < 0)
  933. X        return (warnarch("Corrupt binary pathname", (off_t) namefull));
  934. X    if (name[binary.b_name - 1] != '\0')
  935. X        return (warnarch("Bad binary pathname", (off_t) namefull));
  936. X    return (asb->sb_size % 2);
  937. X}
  938. X
  939. X/*
  940. X * indata()
  941. X *
  942. X * Install data from an archive. Returns given file descriptor.
  943. X */
  944. XSTATIC int
  945. Xindata(fd, size, name)
  946. Xint        fd;
  947. Xreg off_t    size;
  948. Xchar        *name;
  949. X{
  950. X    reg uint    chunk;
  951. X    reg char    *oops;
  952. X    reg int        sparse;
  953. X    reg int        corrupt;
  954. X    auto char    *buf;
  955. X    auto uint    avail;
  956. X
  957. X    corrupt = sparse = 0;
  958. X    oops = NULL;
  959. X    while (size) {
  960. X        corrupt |= inavail(&buf, &avail);
  961. X        size -= (chunk = size < avail ? (uint) size : avail);
  962. X        if (oops == NULL && (sparse = swrite(fd, buf, chunk)) < 0)
  963. X            oops = syserr();
  964. X        inalloc(chunk);
  965. X    }
  966. X    if (corrupt)
  967. X        VOID warn(name, "Corrupt archive data");
  968. X    if (oops)
  969. X        VOID warn(name, oops);
  970. X    else if (sparse > 0
  971. X      && (lseek(fd, (off_t) -1, 1) < 0
  972. X        || write(fd, "", 1) != 1))
  973. X        VOID warn(name, syserr());
  974. X    return (fd);
  975. X}
  976. X
  977. X/*
  978. X * inentry()
  979. X *
  980. X * Install a single archive entry. Returns zero if successful, -1 otherwise.
  981. X */
  982. XSTATIC int
  983. Xinentry(name, asb)
  984. Xchar        *name;
  985. Xreg Stat    *asb;
  986. X{
  987. X    reg Link    *linkp;
  988. X    reg int        ifd;
  989. X    reg int        ofd;
  990. X    auto time_t    tstamp[2];
  991. X
  992. X    if ((ofd = openo(name, asb, linkp = linkfrom(asb), 0)) > 0)
  993. X        if (asb->sb_size || linkp == NULL || linkp->l_size == 0)
  994. X            VOID close(indata(ofd, asb->sb_size, name));
  995. X        else if ((ifd = open(linkp->l_path->p_name, O_RDONLY)) < 0)
  996. X            VOID warn(linkp->l_path->p_name, syserr());
  997. X        else {
  998. X            passdata(linkp->l_path->p_name, ifd, name, ofd);
  999. X            VOID close(ifd);
  1000. X            VOID close(ofd);
  1001. X        }
  1002. X    else if (ofd < 0)
  1003. X        return (-1);
  1004. X    else if (inskip(asb->sb_size) < 0)
  1005. X        VOID warn(name, "Redundant file data is corrupt");
  1006. X    tstamp[0] = tstamp[1] = mflag ? timenow : asb->sb_mtime;
  1007. X    VOID utime(name, tstamp);
  1008. X    return (0);
  1009. X}
  1010. X
  1011. X/*
  1012. X * infill()
  1013. X *
  1014. X * Fill the archive buffer. Remembers mid-buffer read failures and
  1015. X * reports them the next time through. Replaces unreadable data with
  1016. X * null characters. Returns zero with valid data, -1 otherwise.
  1017. X */
  1018. XSTATIC int
  1019. Xinfill()
  1020. X{
  1021. X    reg int        got;
  1022. X    static int    failed;
  1023. X
  1024. X    bufend = bufidx = buffer;
  1025. X    if (!failed) {
  1026. X        if (areof)
  1027. X            if (total == 0)
  1028. X                fatal(arspec, "No input");
  1029. X            else
  1030. X                next(O_RDONLY, "Input EOF");
  1031. X        if (aruntil && arleft < arbsize)
  1032. X            next(O_RDONLY, "Input limit reached");
  1033. X        while (!failed
  1034. X            && !areof
  1035. X            && (aruntil == 0 || arleft >= arbsize)
  1036. X            && buffer + buflen - bufend >= arbsize) {
  1037. X            if ((got = read(arfd, bufend, arbsize)) > 0) {
  1038. X                bufend += got;
  1039. X                arleft -= got;
  1040. X            } else if (got < 0)
  1041. X                failed = warnarch(syserr(),
  1042. X                    (off_t) 0 - (bufend - bufidx));
  1043. X            else
  1044. X                ++areof;
  1045. X        }
  1046. X    }
  1047. X    if (failed && bufend == buffer) {
  1048. X        failed = 0;
  1049. X        for (got = 0; got < arbsize; ++got)
  1050. X            *bufend++ = '\0';
  1051. X        return (-1);
  1052. X    }
  1053. X    return (0);
  1054. X}
  1055. X
  1056. X/*
  1057. X * inhead()
  1058. X *
  1059. X * Read a header. Quietly translates old-fashioned binary cpio headers
  1060. X * (and arranges to skip the possible alignment byte). Returns zero if
  1061. X * successful, -1 upon archive trailer.
  1062. X */
  1063. XSTATIC int
  1064. Xinhead(name, asb)
  1065. Xreg char    *name;
  1066. Xreg Stat    *asb;
  1067. X{
  1068. X    reg off_t    skipped;
  1069. X    auto char    magic[M_STRLEN];
  1070. X    static int    align;
  1071. X
  1072. X    if (align > 0)
  1073. X        VOID inskip((off_t) align);
  1074. X    align = 0;
  1075. X    for (;;) {
  1076. X        VOID inread(magic, M_STRLEN);
  1077. X        skipped = 0;
  1078. X        while ((align = inascii(magic, name, asb)) < 0
  1079. X            && (align = inbinary(magic, name, asb)) < 0
  1080. X            && (align = inswab(magic, name, asb)) < 0) {
  1081. X            if (++skipped == 1) {
  1082. X                if (!kflag && total - sizeof(magic) == 0)
  1083. X                    fatal(arspec, "Unrecognizable archive");
  1084. X                VOID warnarch("Bad magic number",
  1085. X                    (off_t) sizeof(magic));
  1086. X                if (name[0])
  1087. X                    VOID warn(name, "May be corrupt");
  1088. X            }
  1089. X            memcpy(magic, magic + 1, sizeof(magic) - 1);
  1090. X            VOID inread(magic + sizeof(magic) - 1, 1);
  1091. X        }
  1092. X        if (skipped) {
  1093. X            VOID warnarch("Apparently resynchronized",
  1094. X                (off_t) sizeof(magic));
  1095. X            VOID warn(name, "Continuing");
  1096. X        }
  1097. X        if (strcmp(name, TRAILER) == 0)
  1098. X            return (-1);
  1099. X        if (nameopt(name) >= 0)
  1100. X            break;
  1101. X        VOID inskip(asb->sb_size + align);
  1102. X    }
  1103. X#ifdef    S_IFLNK
  1104. X    if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
  1105. X        if (inread(asb->sb_link, (uint) asb->sb_size) < 0) {
  1106. X            VOID warn(name, "Corrupt symbolic link");
  1107. X            return (inhead(name, asb));
  1108. X        }
  1109. X        asb->sb_link[asb->sb_size] = '\0';
  1110. X        asb->sb_size = 0;
  1111. X    }
  1112. X#endif    /* S_IFLNK */
  1113. X    if (name[0] == '/')
  1114. X        if (name[1])
  1115. X            while (name[0] = name[1])
  1116. X                ++name;
  1117. X        else
  1118. X            name[0] = '.';
  1119. X    asb->sb_atime = asb->sb_ctime = asb->sb_mtime;
  1120. X    return (0);
  1121. X}
  1122. X
  1123. X/*
  1124. X * inread()
  1125. X *
  1126. X * Read a given number of characters from the input archive. Returns
  1127. X * zero with valid data, -1 if unreadable portions were replaced by
  1128. X * null characters.
  1129. X */
  1130. XSTATIC int
  1131. Xinread(dst, len)
  1132. Xreg char    *dst;
  1133. Xuint        len;
  1134. X{
  1135. X    reg uint    have;
  1136. X    reg uint    want;
  1137. X    reg int        corrupt = 0;
  1138. X    char        *endx = dst + len;
  1139. X
  1140. X    while (want = endx - dst) {
  1141. X        while ((have = bufend - bufidx) == 0)
  1142. X            corrupt |= infill();
  1143. X        if (have > want)
  1144. X            have = want;
  1145. X        memcpy(dst, bufidx, have);
  1146. X        bufidx += have;
  1147. X        dst += have;
  1148. X        total += have;
  1149. X    }
  1150. X    return (corrupt);
  1151. X}
  1152. X
  1153. X/*
  1154. X * inskip()
  1155. X *
  1156. X * Skip input archive data. Returns zero under normal circumstances,
  1157. X * -1 if unreadable data is encountered.
  1158. X */
  1159. XSTATIC int
  1160. Xinskip(len)
  1161. Xreg off_t    len;
  1162. X{
  1163. X    reg uint    chunk;
  1164. X    reg int        corrupt = 0;
  1165. X
  1166. X    while (len) {
  1167. X        while ((chunk = bufend - bufidx) == 0)
  1168. X            corrupt |= infill();
  1169. X        if (chunk > len)
  1170. X            chunk = len;
  1171. X        bufidx += chunk;
  1172. X        len -= chunk;
  1173. X        total += chunk;
  1174. X    }
  1175. X    return (corrupt);
  1176. X}
  1177. X
  1178. X/*
  1179. X * inswab()
  1180. X *
  1181. X * Read a reversed byte order binary header. Returns the number
  1182. X * of trailing alignment bytes to skip; -1 if unsuccessful.
  1183. X */
  1184. XSTATIC int
  1185. Xinswab(magic, name, asb)
  1186. Xreg char    *magic;
  1187. Xreg char    *name;
  1188. Xreg Stat    *asb;
  1189. X{
  1190. X    reg ushort    namesize;
  1191. X    reg uint    namefull;
  1192. X    auto Binary    binary;
  1193. X
  1194. X    if (*((ushort *) magic) != swab(M_BINARY))
  1195. X        return (-1);
  1196. X    memcpy((char *) &binary,
  1197. X        magic + sizeof(ushort),
  1198. X        M_STRLEN - sizeof(ushort));
  1199. X    if (inread((char *) &binary + M_STRLEN - sizeof(ushort),
  1200. X        sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0)
  1201. X        return (warnarch("Corrupt swapped header",
  1202. X            (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  1203. X    asb->sb_dev = (dev_t) swab(binary.b_dev);
  1204. X    asb->sb_ino = (ino_t) swab(binary.b_ino);
  1205. X    asb->sb_mode = swab(binary.b_mode);
  1206. X    asb->sb_uid = swab(binary.b_uid);
  1207. X    asb->sb_gid = swab(binary.b_gid);
  1208. X    asb->sb_nlink = swab(binary.b_nlink);
  1209. X    asb->sb_rdev = (dev_t) swab(binary.b_rdev);
  1210. X    asb->sb_mtime = swab(binary.b_mtime[0]) << 16 | swab(binary.b_mtime[1]);
  1211. X    asb->sb_size = swab(binary.b_size[0]) << 16 | swab(binary.b_size[1]);
  1212. X    if ((namesize = swab(binary.b_name)) == 0 || namesize >= PATHSIZE)
  1213. X        return (warnarch("Bad swapped pathname length",
  1214. X            (off_t) sizeof(binary) - (M_STRLEN - sizeof(ushort))));
  1215. X    if (inread(name, namefull = namesize + namesize % 2) < 0)
  1216. X        return (warnarch("Corrupt swapped pathname", (off_t) namefull));
  1217. X    if (name[namesize - 1] != '\0')
  1218. X        return (warnarch("Bad swapped pathname", (off_t) namefull));
  1219. X    return (asb->sb_size % 2);
  1220. X}
  1221. X
  1222. X/*
  1223. X * lineget()
  1224. X *
  1225. X * Get a line from a given stream. Returns 0 if successful, -1 at EOF.
  1226. X */
  1227. XSTATIC int
  1228. Xlineget(stream, buf)
  1229. Xreg FILE    *stream;
  1230. Xreg char    *buf;
  1231. X{
  1232. X    reg int        c;
  1233. X
  1234. X    for (;;) {
  1235. X        if ((c = getc(stream)) == EOF)
  1236. X            return (-1);
  1237. X        if (c == '\n')
  1238. X            break;
  1239. X        *buf++ = c;
  1240. X    }
  1241. X    *buf = '\0';
  1242. X    return (0);
  1243. X}
  1244. X
  1245. X/*
  1246. X * linkalso()
  1247. X *
  1248. X * Add a destination pathname to an existing chain. Assumes that
  1249. X * at least one element is present.
  1250. X */
  1251. XSTATIC void
  1252. Xlinkalso(linkp, name)
  1253. Xreg Link    *linkp;
  1254. Xchar        *name;
  1255. X{
  1256. X    reg Path    *path;
  1257. X
  1258. X    if ((path = (Path *) memget(sizeof(Path))) == NULL
  1259. X        || (path->p_name = memstr(name)) == NULL)
  1260. X        return;
  1261. X    path->p_forw = NULL;
  1262. X    path->p_back = linkp->l_path->p_back;
  1263. X    path->p_back->p_forw = path;
  1264. X    linkp->l_path->p_back = path;
  1265. X}
  1266. X
  1267. X/*
  1268. X * linkfrom()
  1269. X *
  1270. X * Find a file to link from. Returns a pointer to a link
  1271. X * structure, or NULL if unsuccessful.
  1272. X */
  1273. XSTATIC Link *
  1274. Xlinkfrom(asb)
  1275. Xreg Stat    *asb;
  1276. X{
  1277. X    reg Link    *linkp;
  1278. X    reg Link    *linknext;
  1279. X    reg Path    *path;
  1280. X    reg Path    *pathnext;
  1281. X    reg Link    **abase;
  1282. X
  1283. X    for (linkp = *(abase = linkhash(asb->sb_ino)); linkp; linkp = linknext)
  1284. X        if (linkp->l_nlink == 0) {
  1285. X            for (path = linkp->l_path; path; path = pathnext) {
  1286. X                pathnext = path->p_forw;
  1287. X                free(path->p_name);
  1288. X            }
  1289. X            free((char *) linkp->l_path);
  1290. X            if (linknext = linkp->l_forw)
  1291. X                linknext->l_back = linkp->l_back;
  1292. X            if (linkp->l_back)
  1293. X                linkp->l_back->l_forw = linkp->l_forw;
  1294. X            else
  1295. X                *abase = linkp->l_forw;
  1296. X            free((char *) linkp);
  1297. X        } else if (linkp->l_ino == asb->sb_ino
  1298. X            && linkp->l_dev == asb->sb_dev) {
  1299. X            --linkp->l_nlink;
  1300. X            return (linkp);
  1301. X        } else
  1302. X            linknext = linkp->l_forw;
  1303. X    return (NULL);
  1304. X}
  1305. X
  1306. END_OF_FILE
  1307. if test 29675 -ne `wc -c <'afio.c.P1'`; then
  1308.     echo shar: \"'afio.c.P1'\" unpacked with wrong size!
  1309. fi
  1310. # end of 'afio.c.P1'
  1311. fi
  1312. echo shar: End of archive 2 \(of 2\).
  1313. ##  End of shell archive.
  1314. exit 0
  1315.